/** @file    EncodersPlainText_Core.cpp
 *  @author  Alessandro Polo
 *  @version $Id: EncodersPlainText_Core.cpp 2697 2010-06-22 17:59:00Z alex $
 *  @brief
 * The header for this class can be found in EncodersPlainText_Core.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/
 
 #include <framework/persistence/plaintext/EncodersPlainText_Core.h>

 #include <core/ObjectAllocator.h>


namespace wosh {
 namespace persistence {
  namespace plaintext {

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_Encoder_PlainText_BIND(wosh::persistence::plaintext::EncoderPlainText_List, "wosh::List", 0.0, _static_EncoderPlainText_List )

WRESULT EncoderPlainText_List::serializeTo( const wosh::List* object, std::ostream& output_stream, int encoder_options ) {
	if ( object == NULL ) return WRET_ERR_PARAM;
	List::ConstIterator it;
	const List::ConstIterator it_end = object->end();
	for( it=object->begin(); it!=object->end(); ++it ) {
		if ( *it == NULL ) continue;
		EncoderProtocolPlainText::serializeTo( *it, output_stream, encoder_options );
		output_stream << std::endl;
	 } 
	output_stream << std::flush;
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_Encoder_PlainText_BIND(wosh::persistence::plaintext::EncoderPlainText_Notification, "wosh::Notification", 0.0, _static_EncoderPlainText_Notification )

WRESULT EncoderPlainText_Notification::serializeTo( const wosh::Notification* object, std::ostream& output_stream, int encoder_options ) {
	if ( object == NULL ) return WRET_ERR_PARAM;
	if ( isCompact(encoder_options) ) {
		output_stream << "ID: " << object->getID() << " [" << object->getFlowID() << "]" << std::endl;
		output_stream << "TimeStamp: " << object->getTimeStamp() << ", Sent At: " << object->getSentTimeStamp() << ", Read At: " << object->getReadTimeStamp() << std::endl;
		output_stream << "Sender: " << object->getSender_User() << " [" << object->getSender_ID() << "]" << std::endl;
		output_stream << "Recipent: " << object->getRecipent_User();
		if ( !object->getRecipent_Group().empty() ) output_stream << "::" << object->getRecipent_Group();
		output_stream << " [" << object->getRecipent_ID() << "]" << std::endl;
	 }
	else {
		output_stream << "ID: " << object->getID() << std::endl;
		output_stream << "FlowID: " << object->getFlowID() << std::endl;
		output_stream << "TimeStamp: " << object->getTimeStamp() << std::endl;
		output_stream << "Sent At: " << object->getSentTimeStamp() << ", Read At: " << object->getReadTimeStamp() << std::endl;
		output_stream << "Sender: " << object->getSender_User() << " [" << object->getSender_ID() << "]" << std::endl;
		output_stream << "Recipent: " << object->getRecipent_User();
		if ( !object->getRecipent_Group().empty() ) output_stream << "::" << object->getRecipent_Group();
		output_stream << " [" << object->getRecipent_ID() << "]" << std::endl;
		output_stream << "Language: " << object->getLanguage() << std::endl;
		output_stream << "PreferredCommunicator: " << object->getPreferredCommunicator().toString() << std::endl;
	 }
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_Encoder_PlainText_BIND(wosh::persistence::plaintext::EncoderPlainText_Object, "wosh::Object", 0.0, _static_EncoderPlainText_Object )

WRESULT EncoderPlainText_Object::serializeTo( const wosh::Object* object, std::ostream& output_stream, int encoder_options ) {
	if ( object == NULL ) return WRET_ERR_PARAM;
	if ( isCompact(encoder_options) ) {
		output_stream << "Name: " << object->getName() << "' [" << object->getEntityID() << "]" << std::endl;
		output_stream << "URI: " << object->getURI().toString() << std::endl;
	 }
	else {
		output_stream << "ClassName: " << object->getClassName() << std::endl;
		output_stream << "Name: '" << object->getName() << "' [" << object->getEntityID() << "]" << std::endl;
		output_stream << "URI: " << object->getURI().toString() << std::endl;
		output_stream << "Permission: " << object->getPermission().toUnixStyle() << std::endl;
	 }
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_Encoder_PlainText_BIND(wosh::persistence::plaintext::EncoderPlainText_ObjectTypeInfo, "wosh::ObjectTypeInfo", 0.0, _static_EncoderPlainText_ObjectTypeInfo )

WRESULT EncoderPlainText_ObjectTypeInfo::serializeTo( const wosh::ObjectTypeInfo* object, std::ostream& output_stream, int encoder_options ) {
	if ( object == NULL ) return WRET_ERR_PARAM;
	if ( isCompact(encoder_options) ) {
		if ( !object->allocable ) output_stream << "Abstract ";
		output_stream << "Class: " << object->name << "[" << object->version << "]";
		if ( !object->parent.empty() ) {
			output_stream << "(parent: " << object->parent << ")";
		 }
	 }
	else {
		output_stream << "ClassName: " << object->name << "[" << object->version << "]" << std::endl;
		output_stream << "Parent Class: " << object->parent << std::endl;
		output_stream << "Allocable: ";
		if ( object->allocable ) output_stream << "true";
		else output_stream << "false";
		output_stream << std::endl;
	 }
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_Encoder_PlainText_BIND(wosh::persistence::plaintext::EncoderPlainText_Property, "wosh::Property", 0.0, _static_EncoderPlainText_Property )

WRESULT EncoderPlainText_Property::serializeTo( const wosh::Property* object, std::ostream& output_stream, int encoder_options ) {
	if ( object == NULL ) return WRET_ERR_PARAM;
	if ( isCompact(encoder_options) ) {
		output_stream << "Key: '" << object->getKey() << "' Value[" << object->getValue().getTypeAsString(true) << "]: '" << object->getValue().toString() << "'";
		if ( !object->getPermission().isEmpty() )
			output_stream << " Permission: " << object->getPermission().toUnixStyle();
	 }
	else {
		output_stream << "Key: " << object->getKey() << std::endl;
		output_stream << "Value[" << object->getValue().getTypeAsString(true) << "]: '" << object->getValue().toString() << "'" << std::endl;
		output_stream << "Permission: " << object->getPermission().toUnixStyle() << std::endl;
	 }
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_Encoder_PlainText_BIND(wosh::persistence::plaintext::EncoderPlainText_SharedMemoryInfo, "wosh::SharedMemoryInfo", 0.0, _static_EncoderPlainText_SharedMemoryInfo )

WRESULT EncoderPlainText_SharedMemoryInfo::serializeTo( const wosh::SharedMemoryInfo* object, std::ostream& output_stream, int encoder_options ) {
	if ( object == NULL ) return WRET_ERR_PARAM;
	if ( isCompact(encoder_options) ) {
		output_stream << "ID: " << object->id;
		if ( object->primary )	output_stream << "*";
		output_stream << ", Kernel: " << object->kernel << std::endl;
		output_stream << "Seniority: " << object->seniority << " [LastSeen: " << object->lastSeen << "]";
		output_stream << ", Clock: " << object->clock << std::endl;
		output_stream << "Mode: " << object->mode;
		output_stream << ", Strategy: " << object->strategy;
		output_stream << ", Propagation: " << object->propagation << std::endl;
	 }
	else {
		output_stream << "ID: " << object->id << " Kernel: " << object->kernel << std::endl;
		output_stream << "Clock: " << object->clock << std::endl;
		output_stream << "Seniority: " << object->seniority;
		if ( object->primary )	output_stream << " [primary]" << std::endl;
		else	output_stream << " [not primary]" << std::endl;
		output_stream << "Mode: " << object->mode << std::endl;
		output_stream << "Strategy: " << object->strategy << std::endl;
		output_stream << "Propagation: " << object->propagation << std::endl;
		output_stream << "LastSeen: " << object->lastSeen << std::endl;
	 }
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_Encoder_PlainText_BIND(wosh::persistence::plaintext::EncoderPlainText_SystemError, "wosh::SystemError", 0.0, _static_EncoderPlainText_SystemError )

WRESULT EncoderPlainText_SystemError::serializeTo( const wosh::SystemError* object, std::ostream& output_stream, int encoder_options ) {
	if ( object == NULL ) return WRET_ERR_PARAM;
	if ( isCompact(encoder_options) ) {
		output_stream << "ID: " << object->getID() << " TimeStamp: " << object->getTimeStamp() << std::endl;
		output_stream << "Source: " << object->getSource().toString() << std::endl;
		output_stream << "Method: " << object->getMethod() << " [ErrorCode " << object->getErrorCode() << "]" << std::endl;
		output_stream << "Description: " << object->getDescription();
	 }
	else {
		output_stream << "ID: " << object->getID() << std::endl;
		output_stream << "TimeStamp: " << object->getTimeStamp() << std::endl;
		output_stream << "Priority: " << (int)object->getPriority() << std::endl;
		output_stream << "Source: " << object->getSource().toString() << std::endl;
		output_stream << "Method: " << object->getMethod() << " [ErrorCode " << object->getErrorCode() << "]" << std::endl;
		output_stream << "Description: " << object->getDescription() << std::endl;
	 }
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_Encoder_PlainText_BIND(wosh::persistence::plaintext::EncoderPlainText_Table, "wosh::Table", 0.0, _static_EncoderPlainText_Table )

WRESULT EncoderPlainText_Table::serializeTo( const wosh::Table* table, std::ostream& output_stream, int ) {
	if ( table == NULL ) return WRET_ERR_PARAM;
	int* lenghts = new int[table->getCols()];
	int spacing = 1;
	int tot_lenght = 0;
	for(unsigned int col=0; col<table->getCols(); col++) {
		lenghts[col] = 0;
		for(unsigned int row=0; row<table->getRows(); row++) {
			const wosh::ISerializable* object = table->get(row, col);
			int csize = evalStringSize(object, 40);
			if ( csize > lenghts[col] )
				lenghts[col] = csize;
		}
		lenghts[col] += spacing;
		tot_lenght += lenghts[col];
	 }
	if ( table->hasHeaderHorizontal() ) {
		for(unsigned int col=0; col<table->getCols(); col++) {
			const wosh::ISerializable* object = table->getHeaderHorizontal(col);
			int csize = evalStringSize(object, 40);
			if ( csize > lenghts[col] )
				lenghts[col] = csize + spacing;
		 }
	 }
	if ( !table->getTableName().empty() )
		output_stream << table->getTableName() << std::endl;

	if ( table->hasHeaderHorizontal() ) {
		for(unsigned int col=0; col<table->getCols(); col++) {
			output_stream.fill(' ');
			output_stream.width(lenghts[col]);
			const wosh::ISerializable* object = table->getHeaderHorizontal(col);
			//render(object, sbuffer);
			if ( object == NULL ) output_stream << "[NULL]";
			else output_stream << object->toString();
		 }
		output_stream << std::endl;
		output_stream.fill('-');
		output_stream.width(tot_lenght);
		output_stream << "-";
		output_stream << std::endl;
	 }
	for(unsigned int row=0; row<table->getRows(); row++) {
		for(unsigned int col=0; col<table->getCols(); col++) {
			output_stream.fill(' ');
			output_stream.width(lenghts[col]);
			const wosh::ISerializable* object = table->get(row, col);
			//render(object, output_stream);
			if ( object == NULL ) output_stream << "[NULL]";
			else output_stream << object->toString();
		 }
		output_stream << std::endl;
	 }
	output_stream << std::endl;
	output_stream << std::flush;
	delete [] lenghts;
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_Encoder_PlainText_BIND(wosh::persistence::plaintext::EncoderPlainText_Tree, "wosh::Tree", 0.0, _static_EncoderPlainText_Tree )

WRESULT EncoderPlainText_Tree::serializeTo( const wosh::Tree* object, std::ostream& output_stream, int encoder_options ) {
	if ( object == NULL ) return WRET_ERR_PARAM;

	if ( !object->hasRoot() )
		output_stream << "(Empty Tree)";
	else {
		EncoderPlainText_TreeNode::serializeTo( object->getRoot(), output_stream, encoder_options); // recursive
	 }
	output_stream << std::endl;
	output_stream << std::flush;

	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_Encoder_PlainText_BIND(wosh::persistence::plaintext::EncoderPlainText_TreeNode, "wosh::TreeNode", 0.0, _static_EncoderPlainText_TreeNode )

WRESULT EncoderPlainText_TreeNode::serializeTo( const wosh::TreeNode* object, std::ostream& output_stream, int encoder_options ) {
	if ( object == NULL ) return WRET_ERR_PARAM;
	if ( object == NULL ) {
		output_stream << "! NULL Node" << std::endl;
		return WRET_OK;
	 }
	int indent = 1;
	output_stream.fill(' ');
	output_stream.width(indent+1);
	if ( object->getChildren().isEmpty() )
		output_stream << "- ";
	else
		output_stream << "+ ";

	const wosh::ISerializable* content = object->getContent();
	EncoderProtocolPlainText::serializeTo( content, output_stream, encoder_options );
	output_stream << std::endl;

	if ( object->getChildren().isEmpty() )
		return WRET_OK;

	TreeNode::ChildConstIterator it;
	const TreeNode::ChildConstIterator it_end = object->getChildren().end();
	for( it=object->getChildren().begin(); it!=it_end; ++it) {
		if ( *it == NULL ) continue;
		const wosh::TreeNode* cNode = dynamic_cast<const TreeNode*>(*it);
		serializeTo(cNode, output_stream, indent+2);
	 }
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
 WOSH_Encoder_PlainText_BIND(wosh::persistence::plaintext::EncoderPlainText_Variant, "wosh::Variant", 0.0, _static_EncoderPlainText_Variant2 )

WRESULT EncoderPlainText_Variant::serializeTo( const ISerializable* object_s, std::ostream& output_stream, int encoder_options ) {
	const wosh::Variant* object = dynamic_cast<const wosh::Variant*>(object_s); if ( object == NULL ) return WRET_ERR_PARAM;
	output_stream << object->toString();
	return WRET_OK;
 }
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_Encoder_PlainText_BIND(wosh::persistence::plaintext::EncoderPlainText_WoshHost, "wosh::WoshHost", 0.0, _static_EncoderPlainText_WoshHost )

WRESULT EncoderPlainText_WoshHost::serializeTo( const wosh::WoshHost* object, std::ostream& output_stream, int encoder_options ) {
	if ( object == NULL ) return WRET_ERR_PARAM;
	if ( isCompact(encoder_options) ) {
		output_stream << "Name: " << object->getName() << std::endl;
		output_stream << "Discovery: ";
		output_stream << " Source: " << object->getDiscoverySource();
		output_stream << "; BindAddress: " << object->getDiscoveryBindAddress();
		output_stream << "; Notify-Frequency: " << object->getNotifyFrequency();
		if ( !object->getNeighbours().empty() ) {
			output_stream << "Protocols:"; serializeVector( object->getProtocols(), output_stream, "; " );
			output_stream << std::endl;
		 }
		if ( !object->getConnections().empty() ) {
			output_stream << "Connections:"; serializeMap( object->getConnections(), output_stream, "]; ", " [" );
			output_stream << std::endl;
		 }
		if ( !object->getNeighbours().empty() ) {
			output_stream << "Neighbours:"; serializeMap( object->getNeighbours(), output_stream, "]; ", " [" );
			output_stream << std::endl;
		 }
	 }
	else {
		EncoderPlainText_Object::serializeTo(object, output_stream, false );
		output_stream << "Discovery:" << std::endl;
		output_stream << " Source: " << object->getDiscoverySource() << std::endl;
		output_stream << " BindAddress: " << object->getDiscoveryBindAddress() << std::endl;
		output_stream << " Notify-Frequency: " << object->getNotifyFrequency() << std::endl;
		output_stream << "Protocols" << std::endl; serializeVector( object->getProtocols(), output_stream, "\r\n " );
		output_stream << "Connections" << std::endl; serializeMap( object->getConnections(), output_stream, "\r\n " );
		output_stream << "Neighbours" << std::endl; serializeMap( object->getNeighbours(), output_stream, "\r\n " );
	 }
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

  }; // namespace plaintext
 }; // namespace persistence
}; // namespace wosh
